<?php

declare(strict_types=1);

namespace app\service\product;

use app\model\Prod;
use app\model\ProdBrand;
use InvalidArgumentException;
use think\Collection;
use think\Paginator;

class BrandService
{
    public function paginate(array $filters, int $page, int $pageSize): Paginator
    {
        $query = ProdBrand::order(['sort' => 'asc', 'id' => 'asc']);

        if (!empty($filters['keyword'])) {
            $keyword = trim((string) $filters['keyword']);
            $query->where(function ($subQuery) use ($keyword) {
                $subQuery->whereLike('name', '%' . $keyword . '%')
                    ->whereOr('slug', 'like', '%' . $keyword . '%')
                    ->whereOr('description', 'like', '%' . $keyword . '%');
            });
        }

        if (isset($filters['is_visible']) && $filters['is_visible'] !== '') {
            $query->where('is_visible', (int) $filters['is_visible']);
        }

        if (!empty($filters['owner_org_id'])) {
            $query->where('owner_org_id', (int) $filters['owner_org_id']);
        }

        return $query->paginate([
            'list_rows' => $pageSize,
            'page' => $page,
        ]);
    }

    public function all(array $filters = []): Collection
    {
        $query = ProdBrand::order(['sort' => 'asc', 'id' => 'asc']);

        if (isset($filters['is_visible']) && $filters['is_visible'] !== '') {
            $query->where('is_visible', (int) $filters['is_visible']);
        }

        if (!empty($filters['owner_org_id'])) {
            $query->where('owner_org_id', (int) $filters['owner_org_id']);
        }

        return $query->select();
    }

    public function findById(int $id): ?ProdBrand
    {
        return ProdBrand::find($id);
    }

    public function create(array $payload): ProdBrand
    {
        $name = trim((string) ($payload['name'] ?? ''));
        $slug = trim((string) ($payload['slug'] ?? ''));

        if ($name === '') {
            throw new InvalidArgumentException('品牌名称不能为空');
        }

        if ($slug === '') {
            throw new InvalidArgumentException('品牌编码不能为空');
        }

        $this->assertSlugUnique($slug);

        $data = $this->extractPayload($payload);
        $data['name'] = $name;
        $data['slug'] = $slug;

        /** @var ProdBrand $brand */
        $brand = ProdBrand::create($data);

        return $this->findById((int) $brand->id);
    }

    public function update(ProdBrand $brand, array $payload): ProdBrand
    {
        $data = $this->extractPayload($payload);

        if (array_key_exists('name', $payload)) {
            $name = trim((string) $payload['name']);
            if ($name === '') {
                throw new InvalidArgumentException('品牌名称不能为空');
            }
            $data['name'] = $name;
        }

        if (array_key_exists('slug', $payload)) {
            $slug = trim((string) $payload['slug']);
            if ($slug === '') {
                throw new InvalidArgumentException('品牌编码不能为空');
            }
            if ($slug !== $brand->slug) {
                $this->assertSlugUnique($slug, (int) $brand->id);
            }
            $data['slug'] = $slug;
        }

        $brand->save($data);

        return $this->findById((int) $brand->id);
    }

    public function delete(ProdBrand $brand): bool
    {
        $productExists = Prod::where('brand_id', $brand->id)->count() > 0;
        if ($productExists) {
            throw new InvalidArgumentException('品牌仍有关联商品，无法删除');
        }

        return (bool) $brand->delete();
    }

    public function format(ProdBrand $brand): array
    {
        return [
            'id' => (int) $brand->id,
            'name' => $brand->name,
            'slug' => $brand->slug,
            'logo_url' => $brand->logo_url,
            'banner_url' => $brand->banner_url,
            'description' => $brand->description,
            'content' => $brand->content,
            'origin_country' => $brand->origin_country,
            'owner_org_id' => $brand->owner_org_id ? (int) $brand->owner_org_id : null,
            'sort' => (int) $brand->sort,
            'is_visible' => (int) $brand->is_visible,
            'create_time' => $brand->create_time,
            'update_time' => $brand->update_time,
        ];
    }

    public function formatCollection(iterable $brands): array
    {
        $results = [];
        foreach ($brands as $brand) {
            if ($brand instanceof ProdBrand) {
                $results[] = $this->format($brand);
            }
        }

        return $results;
    }

    private function extractPayload(array $payload): array
    {
        $fields = [
            'logo_url',
            'banner_url',
            'description',
            'content',
            'origin_country',
            'owner_org_id',
            'sort',
            'is_visible',
        ];

        $data = array_intersect_key($payload, array_flip($fields));

        if (array_key_exists('owner_org_id', $data) && $data['owner_org_id'] !== null && $data['owner_org_id'] !== '') {
            $data['owner_org_id'] = (int) $data['owner_org_id'];
        } else {
            $data['owner_org_id'] = null;
        }

        if (array_key_exists('sort', $data)) {
            $data['sort'] = (int) $data['sort'];
        }

        if (array_key_exists('is_visible', $data)) {
            $data['is_visible'] = (int) $data['is_visible'];
        }

        return $data;
    }

    private function assertSlugUnique(string $slug, ?int $excludeId = null): void
    {
        $query = ProdBrand::where('slug', $slug);
        if ($excludeId !== null) {
            $query->where('id', '<>', $excludeId);
        }

        if ($query->count() > 0) {
            throw new InvalidArgumentException('品牌编码已存在');
        }
    }
}
